﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="HttpContextExtensions.cs" company="">
//   
// </copyright>
// <summary>
//   The http context extensions.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Skymate.Mvc.Extensions
{
    using System;
    using System.IO;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;

    using Skymate.Core.IO;
    using Skymate.Extensions;
    using Skymate.Utilities;

    /// <summary>
    /// The http context extensions.
    /// </summary>
    public static class HttpContextExtensions
    {
        /// <summary>
        /// The is admin area.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsAdminArea(this HttpRequest request)
        {
            if (request != null)
            {
                return IsAdminArea(new HttpRequestWrapper(request));
            }

            return false;
        }

        /// <summary>
        /// The is admin area.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsAdminArea(this HttpRequestBase request)
        {
            try
            {
                if (request != null)
                {
                    var area = request.RequestContext.RouteData.GetAreaName();
                    if (area != null)
                    {
                        return area.IsCaseInsensitiveEqual("admin");
                    }
                }

                return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// The is public area.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsPublicArea(this HttpRequest request)
        {
            if (request != null)
            {
                return IsPublicArea(new HttpRequestWrapper(request));
            }

            return false;
        }

        /// <summary>
        /// The is public area.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool IsPublicArea(this HttpRequestBase request)
        {
            try
            {
                if (request != null)
                {
                    var area = request.RequestContext.RouteData.GetAreaName();
                    return area.IsEmpty();
                }

                return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// The to file stream.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <param name="fileName">
        /// The file name.
        /// </param>
        /// <param name="contentType">
        /// The content type.
        /// </param>
        /// <param name="paramName">
        /// The param name.
        /// </param>
        /// <returns>
        /// The <see cref="Stream"/>.
        /// </returns>
        public static Stream ToFileStream(
            this HttpRequestBase request, 
            out string fileName, 
            out string contentType, 
            string paramName = "qqfile")
        {
            fileName = contentType = string.Empty;
            Stream stream = null;

            if (request[paramName].HasValue())
            {
                stream = request.InputStream;
                fileName = request[paramName];
            }
            else
            {
                if (request.Files.Count > 0)
                {
                    stream = request.Files[0].InputStream;
                    contentType = request.Files[0].ContentType;
                    fileName = Path.GetFileName(request.Files[0].FileName);
                }
            }

            if (contentType.IsEmpty())
            {
                contentType = MimeTypes.MapNameToMimeType(fileName);
            }

            return stream;
        }

        /// <summary>
        /// The get route data.
        /// </summary>
        /// <param name="httpContext">
        /// The http context.
        /// </param>
        /// <returns>
        /// The <see cref="RouteData"/>.
        /// </returns>
        public static RouteData GetRouteData(this HttpContextBase httpContext)
        {
            Guard.ArgumentNotNull(() => httpContext);

            var handler = httpContext.Handler as MvcHandler;
            if (handler != null && handler.RequestContext != null)
            {
                return handler.RequestContext.RouteData;
            }

            return null;
        }

        /// <summary>
        /// The try get route data.
        /// </summary>
        /// <param name="httpContext">
        /// The http context.
        /// </param>
        /// <param name="routeData">
        /// The route data.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool TryGetRouteData(this HttpContextBase httpContext, out RouteData routeData)
        {
            routeData = httpContext.GetRouteData();
            return routeData != null;
        }
        
        /// <summary>
        /// The get user theme choice from cookie.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        internal static string GetUserThemeChoiceFromCookie(this HttpContextBase context)
        {
            if (context == null)
            {
                return null;
            }

            var cookie = context.Request.Cookies.Get("sm.UserThemeChoice");
            if (cookie != null)
            {
                return cookie.Value.NullEmpty();
            }

            return null;
        }

        /// <summary>
        /// The set user theme choice in cookie.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        internal static void SetUserThemeChoiceInCookie(this HttpContextBase context, string value)
        {
            if (context == null)
            {
                return;
            }

            var cookie = context.Request.Cookies.Get("sm.UserThemeChoice");

            if (value.HasValue() && cookie == null)
            {
                cookie = new HttpCookie("sm.UserThemeChoice");
                cookie.HttpOnly = true;
                cookie.Expires = DateTime.UtcNow.AddYears(1);
            }

            if (value.HasValue())
            {
                cookie.Value = value;
                context.Request.Cookies.Set(cookie);
            }

            if (value.IsEmpty() && cookie != null)
            {
                cookie.Expires = DateTime.UtcNow.AddYears(-10);
            }

            if (cookie != null)
            {
                context.Response.SetCookie(cookie);
            }
        }

        /// <summary>
        /// The get preview mode cookie.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="createIfMissing">
        /// The create if missing.
        /// </param>
        /// <returns>
        /// The <see cref="HttpCookie"/>.
        /// </returns>
        internal static HttpCookie GetPreviewModeCookie(this HttpContextBase context, bool createIfMissing)
        {
            if (context == null)
            {
                return null;
            }

            var cookie = context.Request.Cookies.Get("sm.PreviewModeOverrides");

            if (cookie == null && createIfMissing)
            {
                cookie = new HttpCookie("sm.PreviewModeOverrides");
                cookie.HttpOnly = true;
                context.Request.Cookies.Set(cookie);
            }

            if (cookie != null)
            {
                // when cookie gets created or touched, extend its lifetime
                cookie.Expires = DateTime.UtcNow.AddMinutes(20);
            }

            return cookie;
        }

        /// <summary>
        /// The set preview mode value.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        internal static void SetPreviewModeValue(this HttpContextBase context, string key, string value)
        {
            if (context == null)
            {
                return;
            }

            var cookie = context.GetPreviewModeCookie(value.HasValue());
            if (cookie != null)
            {
                if (value.HasValue())
                {
                    cookie.Values[key] = value;
                }
                else
                {
                    cookie.Values.Remove(key);
                }
            }
        }

        /// <summary>
        /// The preview mode cookie.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <returns>
        /// The <see cref="IDisposable"/>.
        /// </returns>
        public static IDisposable PreviewModeCookie(this HttpContextBase context)
        {
            var disposable = new ActionDisposable(
                () =>
                    {
                        var cookie = GetPreviewModeCookie(context, false);
                        if (cookie != null)
                        {
                            if (!cookie.HasKeys)
                            {
                                cookie.Expires = DateTime.UtcNow.AddYears(-10);
                            }
                            else
                            {
                                cookie.Expires = DateTime.UtcNow.AddMinutes(20);
                            }

                            context.Response.SetCookie(cookie);
                        }
                    });

            return disposable;
        }
    }
}